﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

using Resxus.Model;
using System.Resources;
using System.Collections;

using Resxus.DataAccess;
using System.Windows;

using System.Windows.Input;
using Microsoft.Windows.Controls;
using System.Diagnostics;

using Resxus.Util;

namespace Resxus.ViewModel
{
    public class ResourceEditVM : WorkspaceViewModel
    {

    #region Fields
                
        /// <summary>
        /// 이 VM 과 연결된 저장소
        /// </summary>
        ResourceTable Repository { get; set; }
        IEdit Control { get; set; }

        /// <summary>
        /// 이 리소스와 관련된 파일
        /// </summary>
        public ResourceFile File
        {
            get;
            private set;
        }

        /// <summary>
        /// 현재창에서 빠른검색 결과
        /// </summary>
        private IEnumerable<ResourceRecord> _SearchResults = null;
        IEnumerable<ResourceRecord> SearchResults 
        { 
            get
            {
                return _SearchResults;
            }
            set
            {
                _SearchResults = value;
                this.OnPropertyChanged("SearchResultsCount");
            }
        }
        
    #endregion //Fields

    #region Events

        /// <summary>
        /// 특정 아이템이 있는 위치로 스크롤 해야 할 경우 호출되는 이벤트 입니다.
        /// </summary>
        public event Action<ResourceRecord> RequestScrollToView;

    #endregion

        #region Constructor

        public ResourceEditVM(IEdit control, ResourceTable repository)
        {
            this.Repository = repository;
            this.File = repository.File;
            this.Control = control;
                        

            this.Repository.AddRecord += new Action<ResourceRecord>(Repository_AddRecord);
            this.Repository.RemoveRecord += new Action<ResourceRecord>(Repository_RemoveRecord);
            this.Repository.ClearRecords += new Action(Repository_ClearRecords);

            this.Repository.DataChanged += new Action<object, DataChangedEventArgs<ResourceRecord>>(Repository_DataChanged);

            this.RequestClose += new EventHandler(ResourceEditVM_RequestClose);         
        }
                      
    #endregion //Constructor

    #region Commands

        /// <summary>
        /// 자세한 검색 설정
        /// </summary>
        ICommand _AdvancedSearchCommand = null;
        public ICommand AdvancedSearchCommand
        {
            get
            {
                if (_AdvancedSearchCommand == null)
                {
                    _AdvancedSearchCommand = new RelayCommand(pararm => AdvancedSearch());
                }
                return _AdvancedSearchCommand;
            }
        }

        /// <summary>
        /// 이전 검색결과로 이동
        /// </summary>
        ICommand _SearchPrevCommand = null;
        public ICommand SearchPrevCommand
        {
            get
            {
                if (_SearchPrevCommand == null)
                {
                    _SearchPrevCommand = new RelayCommand(pararm => SearchPrev(),
                                                          param => { return (this.SearchResultsCount > 0) && 
                                                                            (this.SelectedSearchResultIndex > 1) && 
                                                                            !this.SearchText.Trim().Equals(string.Empty); });
                }
                return _SearchPrevCommand;
            }
        }
        
        /// <summary>
        /// 다음 검색 결과로 이동
        /// </summary>
        ICommand _SearchNextCommand = null;
        public ICommand SearchNextCommand
        {
            get
            {
                if (_SearchNextCommand == null)
                {
                    _SearchNextCommand = new RelayCommand(pararm => SearchNext(),
                                                          param => { return (this.SearchResultsCount > 0) && 
                                                                            (this.SelectedSearchResultIndex < this.SearchResultsCount) && 
                                                                            !this.SearchText.Trim().Equals(string.Empty); });
                }
                return _SearchNextCommand;
            }
        }

        /// <summary>
        /// 새 리소스 레코드 추가
        /// </summary>
        ICommand _AddCommand = null;
        public ICommand AddCommand
        {
            get
            {
                if (_AddCommand  == null)
                {
                    _AddCommand = new RelayCommand(pararm => Add());
                }
                return _AddCommand;
            }
        }
   
        /// <summary>
        /// 현재 리소스 레코드 삭제
        /// </summary>
        ICommand _DeleteCommand = null;
        public ICommand DeleteCommand
        {
            get
            {
                if (_DeleteCommand == null)
                {
                    _DeleteCommand = new RelayCommand(pararm => Delete(), (param) => { return (bool)(this.SelectedRecord != null);});
                }
                return _DeleteCommand;
            }
        }
            
        /// <summary>
        /// 현재 리소스 레코드 복사
        /// </summary>
        ICommand _CopyCommand = null;
        public ICommand CopyCommand
        {
            get
            {
                if (_CopyCommand  == null)
                {
                    _CopyCommand  = new RelayCommand(pararm => Copy(), (param) => { return (bool)(this.SelectedRecord != null);});
                }
                return _CopyCommand;
            }
        }
     
        /// <summary>
        /// 현재 리소스 레코드 잘라내기
        /// </summary>
        ICommand _CutCommand = null;
        public ICommand CutCommand
        {
            get
            {
                if (_CutCommand  == null)
                {
                    _CutCommand = new RelayCommand(pararm => Cut(), (param) => { return (bool)(this.SelectedRecord != null); });
                }
                return _CutCommand;
            }
        }
   
        /// <summary>
        /// 현재 리소스 레코드 붙여넣기
        /// </summary>
        ICommand _PasteCommand = null;
        public ICommand PasteCommand
        {
            get
            {
                if (_PasteCommand  == null)
                {
                    _PasteCommand = new RelayCommand(pararm => Paste(), (param) => { return (bool)(this.SelectedRecord != null); });
                }
                return _PasteCommand;
            }
        }        

    #endregion //Commands

    #region Binding Properties
        
        /// <summary>
        /// 현재 선택된 검색결과 번호
        /// </summary>
        public int SelectedSearchResultIndex
        {
            get
            {
                return _SelectedSearchResultIndex;
            }
            private set
            {
                _SelectedSearchResultIndex = value;
                OnPropertyChanged("SelectedSearchResultIndex");
            }               
        }
        private int _SelectedSearchResultIndex = 0;

        /// <summary>
        /// 검색된 모든 검색결과수
        /// </summary>        
        public int SearchResultsCount
        {
            get
            {
                if (this.SearchResults != null)
                {
                    return SearchResults.Count();
                }
                else
                {
                    return 0;
                }                
            }          
        }
              
        /// <summary>
        /// 검색텍스트
        /// </summary>        
        public string SearchText
        {
            get
            {
                return _SearchText;
            }

            set
            {
                _SearchText = value;
                OnPropertyChanged("SearchText");

                //엔터를 치면 검색수행
                this.Search(_SearchText);
            }
        }
        string _SearchText = string.Empty;

        /// <summary>
        /// 선택된 레코드
        /// </summary>
        object _SelectedRecord = null;
        public object SelectedRecord
        {
            get
            {
                return _SelectedRecord;
            }
            set
            {
                _SelectedRecord = value;
                OnPropertyChanged("SelectedRecord");
            }
        }

        /// <summary>
        /// 레코드 변경여부 
        /// </summary>        
        public bool IsChanged
        {
            get
            {
                return _IsChanged;
            }            
            set
            {
                _IsChanged = value;
                OnPropertyChanged("IsChanged");

                this.NotifyChange();                
            }
        }
        bool _IsChanged = false;

        /// <summary>
        /// 타이틀 명
        /// </summary>
        public override string DisplayName
        {
            get
            {
                if (base.DisplayName == null)
                {
                    base.DisplayName = this.GetTitle();
                }

                return base.DisplayName; 
            }

            protected set
            {
                base.DisplayName = value;
                OnPropertyChanged("DisplayName");
            }
        }
        
        /// <summary>
        /// 화면 레코드 목록
        /// </summary>
        ObservableCollection<ResourceRecord> _Records = null;
        public ObservableCollection<ResourceRecord> Records
        {
            get
            {
                if (_Records == null)
                {
                    _Records = new ObservableCollection<ResourceRecord>(this.Repository);
                    this.Records.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Records_CollectionChanged);

                }
                return _Records;
            }
        }

        /// <summary>
        /// 총 레코드 
        /// </summary>
        public int TotalRecords
        {
            get
            {
                return this.Records.Count;
            }
        }

    #endregion //Binding Properties

    #region Private Helpers
        
        /// <summary>
        /// 지정한 레코드 위치로 스크롤
        /// </summary>
        /// <param name="record">스크롤할 지점 레코드</param>
        private bool ScrollTo(ResourceRecord record)
        {
            if (this.RequestScrollToView != null)
            {
                this.RequestScrollToView(record);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 지정한 인덱스 위치로 스크롤
        /// </summary>
        /// <param name="list">스크롤 대상이 되는 목록</param>
        /// <param name="index">인덱스</param>
        private bool ScrollTo(IEnumerable<ResourceRecord> list, int index)
        {
            if (list != null && list.Count() > 0)
            {
                int newIndex = this.InRange(index, 0, list.Count() - 1, 0);
                ResourceRecord record = list.ElementAt<ResourceRecord>(newIndex);
                return this.ScrollTo(record);
            }

            return false;
        }
                

        /// <summary>
        /// 이 뷰의 타이틀 얻어오기
        /// </summary>
        /// <returns>타이틀</returns>
        private string GetTitle()
        {
            return string.Format("{0} - {1}", this.File.Name, this.File.Culture);
        }

        /// <summary>
        /// 변경사항통보
        /// </summary>
        private void NotifyChange()
        {
            if (this.IsChanged == true)
            {
                this.DisplayName = string.Format("* {0}", this.GetTitle());
            }
            else
            {
                this.DisplayName = GetTitle();
            }
        }

        /// <summary>
        /// 검색결과 하이라이팅 된 것들을 제거
        /// </summary>
        private void ResetSearchHighlights()
        {
            this.Repository.DoAll<ResourceRecord>((param) => { param.IsMatch = false; });
            this.ScrollTo(this.Records, 0);                          
        }

        /// <summary>
        /// 상세 검색
        /// </summary>
        private void AdvancedSearch()
        {           
            //this.Search(this.SearchText);
        }
        
        /// <summary>
        /// (특정키워드로) 검색
        /// </summary>
        /// <param name="keyword"></param>
        private void Search(string keyword)
        {   
            //Search
            string searchItem = keyword;
            if (searchItem.Trim().Equals(string.Empty) == false)
            {
                IEnumerable<ResourceRecord> list = this.Repository.Items.Where<ResourceRecord>((param) =>
                {                    
                    param.IsMatch = (param.ID.Contains(searchItem) == true) || (param.Value.Contains(searchItem) == true);
                    return param.IsMatch;
                });

                this.SearchResults = list;                
                    
                //탐색 목록의 가장 첫번째 항목으로 이동
                if (this.ScrollTo(list, 0) == true)
                {
                    this.SelectedSearchResultIndex = 1;
                }
            }
            else
            {
                this.SelectedSearchResultIndex = 0;
                this.ResetSearchHighlights();
            }            
        }

        /// <summary>
        /// 인덱스를 범위검사하여 적절한 값을 반환합니다.
        /// </summary>
        /// <param name="nextIndex">검사할 인덱스</param>
        /// <param name="min">최소값</param>
        /// <param name="max">최대값</param>
        /// <param name="orginal">범위를 벗어날때 기본값</param>
        /// <returns>범위조건에 맞춰진 값</returns>
        private int InRange(int Index, int min, int max, int orginal)
        {
            return (min <= Index && Index <= this.SearchResultsCount ? Index : orginal);
        }

        /// <summary>
        /// 이전 찾기결과로 이동
        /// </summary>
        private void SearchPrev()
        {            
            int newIndex = InRange(this.SelectedSearchResultIndex - 1, 1, this.SearchResultsCount, 1);
            if (this.ScrollTo(this.SearchResults, newIndex - 1) == true)
            {
                this.SelectedSearchResultIndex = newIndex;
            }            
        }

        /// <summary>
        /// 다음 찾기결과로 이동
        /// </summary>
        private void SearchNext()
        {   
            int newIndex = InRange(this.SelectedSearchResultIndex + 1, 1, this.SearchResultsCount, this.SearchResultsCount);
            if (this.ScrollTo(this.SearchResults, newIndex - 1) == true)
            {
                this.SelectedSearchResultIndex = newIndex;
            }            
        }

        void Add()
        {

        }

        void Delete()
        {

        }

        void Copy()
        {

        }

        void Cut()
        {

        }

        void Paste()
        {

        }
        
        protected override void OnDispose()
        {
            //뒷정리
            IEdit edit = this.Control;
            edit.Repositories.Items.Remove(this.Repository);

            this.RequestClose -= new EventHandler(ResourceEditVM_RequestClose);
            this.Records.CollectionChanged -= new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Records_CollectionChanged);
            this.Records.Clear();

            base.OnDispose();
        }

    #region EventHandler

        /// <summary>
        /// 레코드 전체 제거시 처리
        /// </summary>
        private void Repository_ClearRecords()
        {
            this.Records.Clear();
        }

        /// <summary>
        /// 저장소에서 레코드 삭제시 처리
        /// </summary>
        /// <param name="obj">삭제된 레코드</param>
        private void Repository_RemoveRecord(ResourceRecord obj)
        {
            if (obj.File.Equals(this.File) == true && this.Records.Contains(obj) == true)
            {
                this.Records.Remove(obj);
            }
        }

        /// <summary>
        /// 저장소에서 레코드 추가시 처리
        /// </summary>
        /// <param name="obj">추가된 레코드</param>
        private void Repository_AddRecord(ResourceRecord obj)
        {
            if (obj.File.Equals(this.File) == true && this.Records.Contains(obj) == false)
            {
                this.Records.Add(obj);
            }
        }

        /// <summary>
        /// Observable Collection이 변경되었을때 이를 통보
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Records_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {            
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:                    
                    this.OnPropertyChanged("TotalRecords");                    
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:                                        
                    this.OnPropertyChanged("TotalRecords");
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    this.OnPropertyChanged("TotalRecords");
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 해당View를 닫을때 VM에서 처리
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ResourceEditVM_RequestClose(object sender, EventArgs e)
        {
            if (this.IsChanged == true)
            {
                MessageBoxResult result = MessageBox.Show("변경된 내용을 저장하고 종료하시겠습니까?", this.DisplayName, MessageBoxButton.YesNo, MessageBoxImage.Information);
                if (result == MessageBoxResult.Yes)
                {
                    this.Control.Save(this.File);
                }          
            }            
        }

        /// <summary>
        /// 데이터 변경 통지 처리        
        /// </summary>
        /// <param name="arg1">통지위치</param>
        /// <param name="arg2">변경된 데이터 내용</param>
        private void Repository_DataChanged(object arg1, DataChangedEventArgs<ResourceRecord> arg2)
        {   
            //데이터가 변경되었다는 플래그 On
            this.IsChanged = true;
        }        

    #endregion //EventHandler      
        
    #endregion //Private Helpers

    #region Public Methods

    #endregion //Public Methods
     
    }
}
